home *** CD-ROM | disk | FTP | other *** search
- static char rcsid[] = "$Author: cck $ $Date: 88/09/16 17:12:10 $";
- static char rcsident[] = "$Header: /src/local/mac/cap/etalk/RCS/aarp.c,v 1.26 88/09/16 17:12:10 cck Rel $";
- static char revision[] = "$Revision: 1.26 $";
-
- /*
- * aarp.c - AppleTalk Address Resolution Protocol handler
- *
- * Copyright (c) 1988 by The Trustees of Columbia University
- * in the City of New York.
- *
- * Permission is granted to any individual or institution to use,
- * copy, or redistribute this software so long as it is not sold for
- * profit, provided that this notice and the original copyright
- * notices are retained. Columbia University nor the author make no
- * representations about the suitability of this software for any
- * purpose. It is provided "as is" without express or implied
- * warranty.
- *
- *
- * Edit History:
- *
- * April 3, 1988 CCKim Created
- * Aug 26, 1988 Moved into seperate module from ethertalk
- *
- */
-
- static char columbia_copyright[] = "Copyright (c) 1988 by The Trustees of \
- Columbia University in the City of New York";
-
- #include <stdio.h>
- #include <ctype.h>
- #include <sys/types.h>
- #include <hash.h>
- #include <sys/socket.h>
- #include <sys/ioctl.h>
- #include <sys/uio.h>
- #include <sys/time.h>
- #include <net/if.h>
- #include <netinet/in.h>
- #include <netinet/if_ether.h>
-
- #include <netat/appletalk.h>
- #include "proto_intf.h"
- #include "ethertalk.h"
- #include "aarp_defs.h"
- #include "aarp.h" /* double checks aarp.h */
- #include "log.h"
-
- #define LOG_LOG 0
- #define LOG_BASE 1
- #define LOG_LOTS 9
-
- private int aarptab_compare();
- private u_int aarp_compress();
- private caddr_t aarptab_new();
- private caddr_t aarptab_init();
- private AARP_ENTRY *aarptab_find();
- private AARP_ENTRY *aarptab_get();
- private int aarptab_delete();
-
- export caddr_t aarp_init();
- export int aarp_get_host_addr();
- export int aarp_resolve();
- export int aarp_insert();
- export int aarp_acquire_etalk_node();
- private aarp_listener();
- private AARP_ENTRY *aarp_find_free_etalk_node();
- private probe_and_request_driver();
- private void aarp_probed();
- private void aarp_reply();
- private void aarp_request();
- private struct ai_host_node *host_node();
-
- /* pointers to host ethernet and broadcast addresess */
- private u_char b_eaddr[EHRD] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-
- /* list of all the node ids: DUMP ONLY */
- private AARP_ENTRY *aarptab_node_list;
-
- private AARP_ENTRY *aarptab_free_list;
-
-
- private int m_aarptab = 0;
- private int m_probe = 0;
- private int f_probe = 0;
-
-
- /* compare two ethertalk node addresses */
- private int
- aarptab_compare(k,node)
- struct ethertalkaddr *k;
- AARP_ENTRY *node;
- {
- /* EtherTalk II fixup */
- return(k->node - node->aae_pa.node);
- }
-
- /* compress an ethertalk node addresses */
- private u_int
- aarptab_compress(k)
- struct ethertalkaddr *k;
- {
- /* EtherTalk II fixup */
- return(k->node);
- }
-
- /* create a new arp table entry based upon the ethertalk node */
- private caddr_t
- aarptab_new(k)
- struct ethertalkaddr *k;
- {
- AARP_ENTRY *en;
-
- if (aarptab_free_list) {
- en = aarptab_free_list; /* get first node */
- aarptab_free_list = en->aae_next; /* and unlink from free list */
- /* if dump, don't need to link into dump table, already there */
- } else {
- if ((en = (AARP_ENTRY *)malloc(sizeof(AARP_ENTRY))) == NULL)
- return(NULL);
- m_aarptab++;
- }
- en->aae_next = aarptab_node_list;
- aarptab_node_list = en;
- en->aae_flags = 0; /* clear flags */
- en->aae_used = 0; /* clear used flag */
- en->aae_ttl = 0; /* clear ttl */
- bcopy(k, &en->aae_pa, sizeof(*k)); /* copy in node address */
- return((caddr_t)en);
- }
-
- /* initial hash table for aarp table */
- private caddr_t
- aarptab_init()
- {
- return(h_new(HASH_POLICY_CHAIN, HASH_TYPE_MULTIPLICATIVE,
- AARP_TAB_SIZE,
- aarptab_compare, aarptab_new, aarptab_compress,
- NULL, NULL, NULL));
- }
-
- /* see if we need to try to speed up hash lookups */
- aarptab_speedup(aih)
- AI_HANDLE *aih;
- {
- struct hash_statistics *s;
- int nbkts;
-
- aih->ai_accesses = 0; /* clear */
- s = h_statistics(aih->ai_aarptab); /* get stats */
- if (s->hs_davg < AI_AARPTAB_REHASH_POINT)
- return; /* nothing to do */
- log(LOG_BASE, "aarp: %d buckets, %d entries",
- s->hs_buckets, s->hs_used);
- log(LOG_BASE, "aarp: arp hash table average lookup distance %d.%02d",
- s->hs_davg / 100, s->hs_davg % 100);
- /* possibly delete old entries */
- if ((s->hs_buckets/2) > s->hs_used) {
- log(LOG_BASE, "aarp: buckets half filled, reconsider hash function");
- return;
- } else {
- nbkts = s->hs_buckets*2;
- }
- log(LOG_BASE, "aarp: rehashing table from %d buckets to %d buckets",
- s->hs_buckets, nbkts);
- h_rehash(aih->ai_aarptab, nbkts);
- }
-
- /* find an aarp table entry given an ethertalk node address */
- private AARP_ENTRY *
- aarptab_find(aih, pa)
- AI_HANDLE *aih;
- struct ethertalkaddr *pa;
- {
- AARP_ENTRY *r;
- if ((r = (AARP_ENTRY *)h_member(aih->ai_aarptab, pa))) {
- #ifdef AARP_DUMP_TABLE
- r->aae_used++; /* used once more */
- #endif
- if (aih->ai_accesses++ > AI_AARPTAB_EVAL_POINT)
- aarptab_speedup(aih);
- }
- return(r);
- }
-
- /* find an aarp table entry given an ethertalk node address */
- /* if not found, return a new entry */
- private AARP_ENTRY *
- aarptab_get(aih, pa)
- AI_HANDLE *aih;
- struct ethertalkaddr *pa;
- {
- AARP_ENTRY *r;
- int d, b;
-
- r = (AARP_ENTRY *)h_operation(HASH_OP_INSERT,aih->ai_aarptab,pa,-1,-1,&d,&b);
- if (r == NULL)
- return(NULL);
- if (r->aae_flags == 0) {
- /* EtherTalk II */
- log(LOG_LOTS, "New AARP mapping for node %d, bkt %d, dist %d\n",
- r->aae_pa.node);
- r->aae_aarptab = aih->ai_aarptab; /* remember */
- } else {
- if (aih->ai_accesses++ > AI_AARPTAB_EVAL_POINT)
- aarptab_speedup(aih);
- }
- #ifdef AARP_DUMP_TABLE
- r->aae_used++; /* bump */
- #endif
- return(r);
- }
-
- #ifdef notdef
- /* delete an aarp table entry */
- private int
- aarptab_delete(aih, aa)
- AI_HANDLE *aih;
- AARP_ENTRY *aa;
- {
-
- aa->aae_flags = 0; /* not okay */
- /* EtherTalk II */
- log(LOG_LOTS, "deleting arp entry: node %d", aa->aae_pa.node);
- en = (AARP_ENTRY *)h_delete(aih->ai_aarptab, aa->aae_pa.node);
- if (en != aa) {
- log(LOG_BASE, "when deleting arp entry, freed entry was %x, wanted %x",
- en, aa);
- }
- aa->aae_next = aarptab_free_list;
- aarptab_free_list = aa; /* mark */
- }
- #endif
-
- /* scan arp table and see if anything needs going */
- aarptab_scan()
- {
- struct timeval tv;
- AARP_ENTRY *n, *np, *en, *t;
-
- np = NULL, n = aarptab_node_list;
- while (n) {
- if (n->aae_ttl <= 0) {
- log(LOG_LOTS, "deleting arp entry: node %d", n->aae_pa.node);
- en = (AARP_ENTRY *)h_delete(n->aae_aarptab, &n->aae_pa);
- if (en != n) {
- log(LOG_BASE, "when deleting arp entry, freed entry was %x, wanted %x",
- en, n);
- }
- if (np)
- np->aae_next = n->aae_next; /* unlink */
- else
- aarptab_node_list = n->aae_next; /* at head of list */
- /* link onto free list */
- t = n->aae_next; /* remember next */
- n->aae_next = aarptab_free_list;
- aarptab_free_list = n; /* mark */ /* delete it */
- n = t; /* advance n */
- continue; /* and skip regular advance */
- } else
- n->aae_ttl--; /* dec. ttl */
- np = n; /* remeber previous */
- n = n->aae_next; /* advance n */
- }
- tv.tv_sec = AARP_SCAN_TIME;
- tv.tv_usec = 0;
- relTimeout(aarptab_scan, 0, &tv, TRUE);
- }
-
- /*
- * initialize AARP module
- *
- * arguments are: dev, devno of the interface
- * maxnodes specfies the maximum number of nodes wanted on this
- * interface (usually one)
- *
- * returns pointer to a AI_HANDLE - as caddr_t
- *
- */
- caddr_t
- aarp_init(dev, devno, maxnodes)
- char *dev;
- int devno;
- int maxnodes;
- {
- int aarp_listener();
- AI_HANDLE *aih = NULL;
- static int here_before = 0;
- int ph = -1;
-
- if (!here_before) {
- struct timeval tv;
-
- here_before = 1;
- aarptab_node_list = NULL; /* clear */
- aarptab_free_list = NULL;
- tv.tv_sec = AARP_SCAN_TIME;
- tv.tv_usec = 0;
- relTimeout(aarptab_scan, 0, &tv, TRUE);
- }
-
- if ((ph = pi_open(ETHERTYPE_AARP, dev, devno)) < 0) {
- log(L_UERR|LOG_LOG,"pi_open: aarp_init");
- return(NULL);
- }
- if ((aih = (AI_HANDLE *)malloc(sizeof(AI_HANDLE))) == NULL)
- goto giveup;
- if ((aih->ai_nodes = (struct ai_host_node *)
- malloc(sizeof(struct ai_host_node)*maxnodes)) == NULL)
- goto giveup;
-
- /* clear host node table */
- bzero(aih->ai_nodes, sizeof(struct ai_host_node)*maxnodes);
- aih->ai_flags = 0; /* clear flags for interface */
- aih->ai_numnode = 0; /* no nodes yet */
- aih->ai_maxnode = maxnodes; /* max # of nodes (usually 1) */
- aih->ai_ph = ph;
- /* get ethernet address */
- if ((pi_get_ethernet_address(ph, aih->ai_eaddr)) < 0)
- goto giveup;
-
- log(LOG_BASE, "Ethernet address for %s%d is %02x:%02x:%02x:%02x:%02x:%02x\n",
- dev, devno,
- aih->ai_eaddr[0], aih->ai_eaddr[1], aih->ai_eaddr[2],
- aih->ai_eaddr[3], aih->ai_eaddr[4], aih->ai_eaddr[5]);
-
- /* setup arp table */
- if ((aih->ai_aarptab = aarptab_init()) == NULL)
- goto giveup;
- aih->ai_accesses = 0; /* no access to table yet */
-
- /* establish listener now */
- pi_listener(aih->ai_ph, aarp_listener, (caddr_t)aih);
- return((caddr_t)aih);
- giveup:
- if (ph >= 0)
- pi_close(ph);
- if (aih) {
- if (aih->ai_nodes)
- free(aih->ai_nodes);
- free(aih);
- }
- return(NULL);
- }
-
- /*
- * get a host node address
- *
- */
- export int
- aarp_get_host_addr(aih, pa, which)
- AI_HANDLE *aih;
- struct ethertalkaddr *pa;
- int which;
- {
- if (aih->ai_numnode > which &&
- aih->ai_nodes[which].aihn_state == AI_NODE_OKAY) {
- *pa = aih->ai_nodes[which].aihn_pa; /* copy it */
- /* should we count pa node address? */
- return(1); /* one byte handled for now */
- }
- return(-1);
- }
-
- /*
- * returns -1: can't be resolved
- * 0: resolving, come back later
- * 1: resolved
- *
- * Resolves the ethernet address of the specified destination.
- * Special cases are:
- * dstnode == 0xff -> broadcast
- * srcnode != ourselves - error
- * dstnode == ourselves - our hw addr (maybe should be error if we
- * can't send to ourselves)
- * In general, algorithm is:
- * check internal table. If entry is valid and if the ttl is valid
- * return the address from the table
- * If not in the table or ttl is bad, then do a request -- however,
- * the current packet WILL drop since the aarp request will not block
- *
- */
- export int
- aarp_resolve(aih, tpa, wantbr, eaddr)
- AI_HANDLE *aih;
- struct ethertalkaddr *tpa;
- int wantbr;
- u_char **eaddr;
- {
- struct timeval *tv;
- AARP_ENTRY *aa;
-
- if (wantbr) {
- *eaddr = b_eaddr; /* want to broadcast */
- return(1);
- }
-
- /* allow target to be ourselves */
- if (host_node(aih, tpa, AI_NODE_OKAY)) {
- *eaddr = aih->ai_eaddr;
- return(0);
- }
-
- /* find the node in the table */
- if ((aa = aarptab_find(aih, tpa)) != NULL && aa->aae_flags & AARP_OKAY) {
- if (aa->aae_flags & (AARP_PERM)) {
- *eaddr = aa->aae_eaddr;
- return(1);
- }
- if (aa->aae_ttl > 0) {
- *eaddr = aa->aae_eaddr; /* yes, return valid */
- return(1);
- }
- }
- /* query on interface */
- aarp_request(aih, aa, tpa);
- return(0);
- }
-
- /*
- * call with hardware address, protocol address
- * flag is TRUE if insert is "hard" FALSE o.w.
- * -- A HARD insert will smash what is there
- * -- A SOFT insert will return FALSE if the ha's don't match and
- * invalidate the cache entry
- * If the insert succeeds, then the ttl is bumped to the normal level
- *
- * Note: aarp_insert performs the gleaning functions of the aarp spec.
- */
- export int
- aarp_insert(aih, ha, pa, hard)
- AI_HANDLE *aih;
- u_char *ha;
- struct ethertalkaddr *pa;
- int hard;
- {
- AARP_ENTRY *aa;
- struct timeval *tv;
-
- /* check to make sure ha isn't broadcast (or multicast)! */
- /* EtherTalk II fixup */
- log(LOG_LOTS, "Got mapping for %d", pa->node);
- dumpether(LOG_LOTS, " Address", ha);
-
- aa = aarptab_get(aih, pa); /* find it or get a new one */
- if (aa->aae_flags & AARP_OKAY) {
- if (aa->aae_flags & (AARP_PERM)) /* don't reset these */
- return(FALSE);
- if (hard)
- /* EtherTalk II fixup */
- log(LOG_LOTS, "Resetting an old mapping for node %d", pa->node);
- }
- /* if arp entry is in cache and we aren't doing a hard update */
- /* and the hardware addresses don't match, don't do an update */
- if ((aa->aae_flags & AARP_OKAY) && !hard) {
- if (bcmp((caddr_t)aa->aae_eaddr, (caddr_t)ha, EHRD) != 0) {
- log(LOG_BASE, "AARP RESET - ethernet address mismatch");
- /* EtherTalk II fixup */
- log(LOG_BASE,"node number is %d", pa->node);
- dumpether(LOG_BASE, "incoming address", ha);
- dumpether(LOG_BASE, "cached address",aa->aae_eaddr);
- aa->aae_flags &= ~AARP_OKAY; /* there we go */
- return(FALSE);
- }
- } else {
- bcopy((caddr_t)pa, (caddr_t)&aa->aae_pa, sizeof(aa->aae_pa));
- bcopy((caddr_t)ha, (caddr_t)aa->aae_eaddr, EHRD); /* copy in mapping */
- aa->aae_flags = AARP_OKAY; /* reset resolving flag if set too */
- }
- aa->aae_ttl = AARP_TTL; /* reset */
- return(TRUE);
- }
-
- /*ARGSUSED*/
- private
- aarp_listener(fd, aih, proth)
- int fd; /* dummy */
- AI_HANDLE *aih;
- int proth;
- {
- struct ethertalkaddr *dpa, *spa;
- byte *sha;
- struct ether_arp arp;
-
- struct ai_host_node *hn;
-
- /* note, we use read protocol because we cannot trust incoming etalk */
- /* addresses from DLI on Ultrix if sent to broadcast */
- if (pi_read(aih->ai_ph, &arp, sizeof(arp)) < 0)
- return;
-
- if (ntohs(arp.arp_hrd) != ARPHRD_ETHER || /* not ethernet? */
- ntohs(arp.arp_pro) != ETHERTYPE_APPLETALK || /* not appletalk? */
- arp.arp_hln != EHRD || /* wrong hrdwr length */
- arp.arp_pln != ETPL) { /* wrong protocol length? */
- /* maybe log? */
- return; /* yes, to one, kill packet */
- }
-
- dpa = (struct ethertalkaddr *)arp.arp_tpa; /* reformat */
- spa = (struct ethertalkaddr *)arp.arp_spa; /* reformat */
- /* copy these because sunos4.0 they are struct's rather than arrays */
- /* and we need to take the address and hate the way the warning */
- /* messages come up, besides saves us a bit on dereferncing */
- sha = (byte *)&arp.arp_sha;
-
- /* check dummy bytes? */
- /* this is the first one of these, so ... the reason we have an & */
- /* in front of an array is that under sunos4.0, arp_sha, etc. are */
- /* now structs */
- if (bcmp((caddr_t)sha, (caddr_t)aih->ai_eaddr, EHRD) == 0) {
- log(LOG_LOTS, "Packet from self");
- return;
- }
- if (host_node(aih, spa, AI_NODE_OKAY)) {
- /* EtherTalk II fixup */
- log(LOG_BASE, "Address conflict %d\n", spa->node);
- }
-
- switch (ntohs(arp.arp_op)) {
- case ARPOP_PROBE:
- if ((hn = host_node(aih, spa, 0))) {
- switch (hn->aihn_state) {
- case AI_NODE_OKAY:
- aarp_reply(aih, &hn->aihn_pa, &arp); /* defend! */
- break;
- case AI_NODE_PROBE:
- hn->aihn_state = AI_NODE_UNUSED;
- break;
- default:
- break;
- }
- break;
- }
- aarp_probed(aih, sha, spa, arp); /* check over entry since we got probe */
- break;
- case ARPOP_REQUEST:
- if (host_node(aih, spa, 0)) /* drop if request from one of */
- break; /* our address */
- /* probably should be more discriminating here */
- /* insert new entry */
- aarp_insert(aih, sha, (struct ethertalkaddr *)arp.arp_spa, TRUE);
- if ((hn = host_node(aih, dpa, AI_NODE_OKAY)))
- aarp_reply(aih, &hn->aihn_pa, &arp);
- break;
- case ARPOP_REPLY:
- /* check to see that dpa isn't one we are probing */
- /* if it is, then things are bad for that potential addr */
-
- if ((hn = host_node(aih, dpa, AI_NODE_PROBE))) {
- hn->aihn_state = AI_NODE_UNUSED;
- break;
- }
- /* drop if source was self (whether ready or not) */
- /* don't need check before here because replies are not broadcast, */
- /* so why would we get it :-) */
- if (host_node(aih, spa, 0))
- break;
- /* mark in our tables */
- aarp_insert(aih, sha, spa, TRUE);
- break;
- }
- }
-
- /* AARP PROBE: some hooks in the listener too */
- /*
- * initialize and start AARP probe process
- *
- */
- struct aarp_aphandle {
- AI_HANDLE *aaph_aih; /* protocol handle */
- AARP_ENTRY *aaph_ae; /* request: point to node handle */
- struct ai_host_node *aaph_node; /* probe: which node # probing */
- struct ether_arp aaph_arp; /* arp */
- int (*aaph_callback)(); /* callback on success on request/probe */
- caddr_t aaph_callback_arg; /* and initial argument */
- int aaph_callback_result; /* this is the result */
- int aaph_tries; /* tries to do */
- };
-
- /*
- * acquire an ethertalk node
- * doesn't try new node address
- * callback is (*callback)(callback_arg, result)
- * where result < 0 if couldn't
- * result >= 0 ==> index of host node address for get host addr
- *
- * return: > 0 - bad node
- * = 0 - okay
- * < 0 - internal error
- *
- */
-
- /* probe state */
- export int
- aarp_acquire_etalk_node(aih, initial_node, callback, callback_arg)
- AI_HANDLE *aih;
- struct ethertalkaddr *initial_node;
- int (*callback)(); /* callback routine */
- caddr_t callback_arg; /* arg for callback */
- {
- struct aarp_aphandle *probe;
- struct ai_host_node *ahn;
- int whichnode = -1;
- int i;
-
- /* bad node */
- /* EtherTalk II fixup */
- if (initial_node->node == 0 || initial_node->node == 255)
- return(1);
- if (aarptab_find(aih, initial_node) || host_node(aih, initial_node, 0)) {
- /* callback ? */
- return(1);
- }
-
- /* get probe structure */
- probe = (struct aarp_aphandle *)malloc(sizeof(struct aarp_aphandle));
- if (probe == NULL)
- return(-1);
- m_probe++;
- for (ahn = aih->ai_nodes, i = 0; i < aih->ai_numnode; i++, ahn++) {
- if (ahn->aihn_state) /* node in use or in probe */
- continue;
- whichnode = i; /* got a good one, ahn set */
- break;
- }
- if (whichnode < 0) { /* no node allocate? */
- if (aih->ai_numnode >= aih->ai_maxnode) /* can't */
- return(-1);
- whichnode = aih->ai_numnode++; /* next node */
- ahn = &aih->ai_nodes[whichnode]; /* get node */
- }
-
- /* initialize probe arp packet */
- bzero(&probe->aaph_arp, sizeof(probe->aaph_arp));
- probe->aaph_arp.arp_hrd = htons(ARPHRD_ETHER);
- probe->aaph_arp.arp_pro = htons(ETHERTYPE_APPLETALK);
- probe->aaph_arp.arp_op = htons(ARPOP_PROBE);
- probe->aaph_arp.arp_hln = EHRD;
- probe->aaph_arp.arp_pln = ETPL;
- bcopy((caddr_t)aih->ai_eaddr, (caddr_t)&probe->aaph_arp.arp_sha, EHRD);
-
- bcopy((caddr_t)initial_node, (caddr_t)probe->aaph_arp.arp_spa, ETPL);
- bcopy((caddr_t)initial_node, (caddr_t)probe->aaph_arp.arp_tpa, ETPL);
-
- probe->aaph_tries = AARP_PROBE_TRY;
-
- probe->aaph_callback = callback;
- probe->aaph_callback_arg = callback_arg;
-
- probe->aaph_aih = aih; /* handle for interface */
- probe->aaph_ae = NULL; /* mark as none */
-
- probe->aaph_callback_result = whichnode; /* mark */
- probe->aaph_node = ahn; /* remember it */
- ahn->aihn_state = AI_NODE_PROBE; /* mark in probe state */
- ahn->aihn_pa = *initial_node; /* copy pa */
-
- /* do first probe */
- probe_and_request_driver(probe);
- return(0); /* okay, we are trying! */
- }
-
- /* main probe and request driver */
- private
- probe_and_request_driver(aphandle)
- struct aarp_aphandle *aphandle;
- {
- register AARP_ENTRY *enp;
-
- struct timeval tv;
- struct ai_host_node *ahn;
- AI_HANDLE *aih = aphandle->aaph_aih;
-
- /* either of these can be running or both - both really doesn't */
- /* make much sense though */
- enp = aphandle->aaph_ae; /* get pointer to node handle */
- ahn = aphandle->aaph_node;
-
- if (enp && ahn) {
- log(LOG_LOG, "internal error: probe and request set in aarp driver\n");
- log(LOG_LOG|L_EXIT, "fatal: please report\n");
- }
-
- if (enp && (enp->aae_flags & AARP_RESOLVING) == 0)
- goto dofree;
- if (ahn && ahn->aihn_state == AI_NODE_UNUSED) {
- /* tell caller that probe for the node address failed */
- if (aphandle->aaph_callback)
- (*aphandle->aaph_callback)(aphandle->aaph_callback_arg, -1);
- goto dofree;
- }
- if (aphandle->aaph_tries <= 0) { /* nothing left to do? */
- /* if we are out of tries, then node has been acquired, hurrah! */
- if (ahn) {
- ahn->aihn_state = AI_NODE_OKAY;
- }
- if (enp) {
- enp->aae_flags &= ~AARP_RESOLVING;
- }
- if (aphandle->aaph_callback)
- (*aphandle->aaph_callback)(aphandle->aaph_callback_arg,
- aphandle->aaph_callback_result);
- goto dofree;
- }
- /* set timeout to next try */
- aphandle->aaph_tries--;
- if (enp) {
- /* should decay based on number of tries */
- tv.tv_sec = AARP_REQUEST_TIMEOUT_SEC;
- tv.tv_usec = AARP_REQUEST_TIMEOUT_USEC;
- }
- if (ahn) {
- /* set timeout to next try */
- tv.tv_sec = AARP_PROBE_TIMEOUT_SEC;
- tv.tv_usec = AARP_PROBE_TIMEOUT_USEC;
- }
- if (pi_write(aih->ai_ph,&aphandle->aaph_arp, sizeof(struct ether_arp),
- b_eaddr) < 0)
- log(LOG_BASE|L_UERR, "pi_write failed: aarp driver");
- /* setup timeout to next (relative timeout) */
- relTimeout(probe_and_request_driver, aphandle, &tv, TRUE);
- return;
- dofree:
- while (remTimeout(probe_and_request_driver, aphandle))
- /* remove while some on queue: NULL STATEMENT */;
- /* address was resolving, nothing left */
- free((caddr_t)aphandle);
- f_probe++;
- }
-
-
- /*
- * got a probe on the specified ha, pa pair and pa is not one of ours
- *
- * mark the mapping pair as suspect. If the specified ha is
- * different, then mark it as very suspect. In both cases, the
- * "suspect" flag is moving down the ttl of the mapping.
- *
- */
- private void
- aarp_probed(aih, ha, pa, arp)
- AI_HANDLE *aih;
- u_char *ha;
- struct ethertalkaddr *pa;
- struct ether_arp *arp;
- {
- AARP_ENTRY *aa;
- struct timeval *tv;
- int nttl;
-
- if ((aa = aarptab_find(aih, pa)) == NULL) /* find entry */
- return; /* nothing */
- if ((aa->aae_flags & AARP_OKAY) == 0) /* nothing to do? */
- return; /* ;right */
- /* get reduction factor on ttl */
- nttl = (bcmp((caddr_t)ha, (caddr_t)aa->aae_eaddr, EHRD) == 0) ?
- AARP_PROBED_SAME : AARP_PROBED_DIFF;
- /* update ttl to lessor of new or old */
- if (nttl < aa->aae_ttl)
- aa->aae_ttl = nttl;
- }
-
- /*
- * reply to an arp request packet
- *
- * note, smashes the arp packet
- *
- */
- private void
- aarp_reply(aih, pa, arp)
- AI_HANDLE *aih;
- struct ethertalkaddr *pa;
- struct ether_arp *arp;
- {
- caddr_t sha, tha;
-
- sha = (caddr_t)&arp->arp_sha; /* need & because can be struct */
- tha = (caddr_t)&arp->arp_tha;
-
- bcopy(sha, tha, EHRD);
- bcopy((caddr_t)arp->arp_spa, (caddr_t)arp->arp_tpa, ETPL);
- arp->arp_op = htons(ARPOP_REPLY);
- bcopy((caddr_t)aih->ai_eaddr, sha, EHRD);
- /* copy in our node */
- bcopy((caddr_t)pa, (caddr_t)arp->arp_spa, ETPL);
- if (pi_write(aih->ai_ph, arp, sizeof(*arp), tha) < 0) {
- log(LOG_LOG|L_UERR, "etsend");
- }
- }
-
- /*
- * do an aarp request
- * - doesn't check that target is ourselves
- */
- private void
- aarp_request(aih, snode, tpa)
- AI_HANDLE *aih;
- AARP_ENTRY *snode;
- struct ethertalkaddr *tpa;
- {
- AARP_ENTRY *aa;
- struct aarp_aphandle *ap;
-
- if ((aa = aarptab_get(aih, tpa)) == NULL) /* get new */
- return;
- if (aa->aae_flags & (AARP_RESOLVING))
- return;
- /* bad condition */
- if (aa->aae_flags & (AARP_PERM))
- return;
- ap = (struct aarp_aphandle *)malloc(sizeof(struct aarp_aphandle));
- m_probe++;
- aa->aae_pa = *tpa;
- aa->aae_flags |= AARP_RESOLVING;
- aa->aae_flags &= ~AARP_OKAY; /* make sure! (can be) */
-
- /* establish arp packet */
- bzero(&ap->aaph_arp, sizeof(ap->aaph_arp));
- ap->aaph_arp.arp_op = htons(ARPOP_REQUEST);
- ap->aaph_arp.arp_hrd = htons(ARPHRD_ETHER);
- ap->aaph_arp.arp_pro = htons(ETHERTYPE_APPLETALK);
- ap->aaph_arp.arp_hln = EHRD;
- ap->aaph_arp.arp_pln = ETPL;
- bcopy((caddr_t)snode->aae_eaddr, (caddr_t)&ap->aaph_arp.arp_sha, EHRD);
- bcopy((caddr_t)&snode->aae_pa, (caddr_t)ap->aaph_arp.arp_spa,
- sizeof(struct ethertalkaddr));
- bcopy((caddr_t)tpa, (caddr_t)ap->aaph_arp.arp_tpa, sizeof(*tpa));
-
- ap->aaph_ae = aa; /* remember this for later */
- ap->aaph_tries = AARP_REQUEST_TRY;
- ap->aaph_node = NULL; /* clear this */
- ap->aaph_aih = aih;
- ap->aaph_callback = NULL;
-
- probe_and_request_driver(ap);
- }
-
-
- /*
- * See if the specified ethertalk address "n" is a host address
- * return true if it is, false o.w.
- *
- * if flag is set, then it indicates that we only want to check against
- * host nodes in the state flag is set to.
- *
- */
- private struct ai_host_node *
- host_node(aih, n, flag)
- AI_HANDLE *aih;
- struct ethertalkaddr *n;
- {
- register int i = aih->ai_numnode;
- register struct ai_host_node *ai_nodes = aih->ai_nodes;
-
- for ( ; i ; ai_nodes++, i--)
- if (ai_nodes->aihn_state) {
- if (flag && ai_nodes->aihn_state != flag)
- continue;
- /* EtherTalk II fixup */
- if (ai_nodes->aihn_pa.node && ai_nodes->aihn_pa.node == n->node)
- return(ai_nodes);
- }
- return(NULL);
- }
-
-
- export
- aarp_dump_stats(fd, ah)
- FILE *fd;
- AI_HANDLE *ah;
- {
- struct hash_statistics *s = h_statistics(ah->ai_aarptab);
-
- fprintf(fd, " aarp hash table statistics, %d nodes in use\n",
- s->hs_used);
- fprintf(fd, "\t%d lookups since last rehash, average distance %.02f\n",
- s->hs_lnum, s->hs_lnum ? ((float)s->hs_lsum / s->hs_lnum) : 0.0);
- fprintf(fd, "\t%d lookups total, average distance %.02f\n",
- s->hs_clnum, s->hs_clnum ? ((float)s->hs_clsum / s->hs_clnum) : 0.0);
- putc('\n', fd);
- fprintf(fd, " %d aarptab entries allocated\n", m_aarptab);
- fprintf(fd, " %d probe/request handles, %d freed\n", m_probe, f_probe);
- putc('\n', fd);
- }
-
- export
- aarp_dump_tables(fd, aih)
- FILE *fd;
- AI_HANDLE *aih;
- {
- AARP_ENTRY *n;
-
- #ifdef AARP_DUMP_TABLE
- fprintf(fd," ARP table dump for interface\n");
- for (n = aarptab_node_list; n ; n = n->aae_next) {
- if (aih->ai_aarptab != n->aae_aarptab || n->aae_flags == 0)
- continue;
- fprintf(fd,
- " node %d, %02x:%02x:%02x:%02x:%02x:%02x, used %d flags %s%s%sttl %d\n",
- n->aae_pa.node,
- n->aae_eaddr[0], n->aae_eaddr[1], n->aae_eaddr[2],
- n->aae_eaddr[3], n->aae_eaddr[4], n->aae_eaddr[5],
- n->aae_used,
- AARP_FNAME_OKAY(n->aae_flags),
- AARP_FNAME_RESOLVING(n->aae_flags),
- AARP_FNAME_PERM(n->aae_flags), n->aae_ttl);
- }
- putc('\n', fd);
- #endif
- }
-